using HDLogCenter.Dal.Repos;
using HDLogCenter.Infrastructure.Models;
using HDLogCenter.Infrastructure.ExternalServices;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using HDLogCenter.Infrastructure.Utils;

namespace HDLogCenter.Infrastructure.Services
{
    public class AlertRuleMonitorService
    {
        private readonly AlertRuleRepo _alertRuleRepo;
        private readonly DingTalkAlertService _dingTalkAlertService;
        private readonly ILogger<AlertRuleMonitorService> _logger;

        // 存储每个项目的错误日志时间戳
        private readonly ConcurrentDictionary<string, List<DateTime>> _errorLogTracker = new ConcurrentDictionary<string, List<DateTime>>();
        // 存储每个项目的最后报警时间，避免重复报警
        private readonly ConcurrentDictionary<string, DateTime> _lastAlertTime = new ConcurrentDictionary<string, DateTime>();
        // 缓存报警规则，避免频繁查询数据库
        private readonly ConcurrentDictionary<string, List<AlertRuleModel>> _alertRulesCache = new ConcurrentDictionary<string, List<AlertRuleModel>>();
        private DateTime _lastCacheUpdate = DateTime.MinValue;
        private readonly TimeSpan _cacheExpiry = TimeSpan.FromMinutes(5); // 缓存5分钟

        public AlertRuleMonitorService(
            AlertRuleRepo alertRuleRepo,
            DingTalkAlertService dingTalkAlertService,
            ILogger<AlertRuleMonitorService> logger)
        {
            _alertRuleRepo = alertRuleRepo;
            _dingTalkAlertService = dingTalkAlertService;
            _logger = logger;
        }

        /// <summary>
        /// 处理日志并检查是否需要触发报警
        /// </summary>
        public async Task HandleLogAsync(LogDto log)
        {
            try
            {
                // 只处理错误级别的日志
                if (log.Level != 1) // 1 = Error
                    return;

                var projectCode = log.Code ?? "Unknown";
                var now = DateTime.UtcNow;

                // 更新错误日志跟踪
                var errorList = _errorLogTracker.GetOrAdd(projectCode, _ => new List<DateTime>());
                lock (errorList)
                {
                    errorList.Add(now);
                    // 清理过期的错误记录（保留最近1小时）
                    errorList.RemoveAll(t => (now - t).TotalHours > 1);
                }

                // 获取该项目的报警规则
                var alertRules = await GetAlertRulesForProjectAsync(projectCode);
                if (alertRules == null || !alertRules.Any())
                {
                    _logger.LogDebug("项目 {ProjectCode} 没有配置报警规则", projectCode);
                    return;
                }

                // 检查每个报警规则
                foreach (var rule in alertRules.Where(r => r.IsEnabled == 1))
                {
                    await CheckAlertRuleAsync(projectCode, rule, errorList, now);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "处理日志报警时发生错误: {Message}", ex.Message);
            }
        }

        /// <summary>
        /// 获取项目的报警规则
        /// </summary>
        private async Task<List<AlertRuleModel>> GetAlertRulesForProjectAsync(string projectCode)
        {
            // 检查缓存是否过期
            if (DateTime.UtcNow - _lastCacheUpdate > _cacheExpiry)
            {
                await RefreshAlertRulesCacheAsync();
            }

            return _alertRulesCache.GetValueOrDefault(projectCode, new List<AlertRuleModel>());
        }

        /// <summary>
        /// 刷新报警规则缓存
        /// </summary>
        private async Task RefreshAlertRulesCacheAsync()
        {
            try
            {
                var allRules = await _alertRuleRepo.GetAllAsync();
                _alertRulesCache.Clear();

                foreach (var rule in allRules)
                {
                    var projectRules = _alertRulesCache.GetOrAdd(rule.ProjectCode, _ => new List<AlertRuleModel>());
                    projectRules.Add(rule);
                }

                _lastCacheUpdate = DateTime.UtcNow;
                _logger.LogInformation("已刷新报警规则缓存，共 {Count} 条规则", allRules.Count());
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "刷新报警规则缓存失败: {Message}", ex.Message);
            }
        }

        /// <summary>
        /// 检查单个报警规则
        /// </summary>
        private async Task CheckAlertRuleAsync(string projectCode, AlertRuleModel rule, List<DateTime> errorList, DateTime now)
        {
            try
            {
                // 计算时间窗口内的错误数量
                var timeWindowStart = now.AddMinutes(-rule.TimeWindow);
                var errorCountInWindow = errorList.Count(t => t >= timeWindowStart);

                _logger.LogDebug("项目 {ProjectCode} 在 {TimeWindow} 分钟内错误数量: {ErrorCount}, 阈值: {Threshold}",
                    projectCode, rule.TimeWindow, errorCountInWindow, rule.ThresholdCount);

                // 检查是否达到阈值
                if (errorCountInWindow >= rule.ThresholdCount)
                {
                    // 检查冷却时间（避免重复报警）
                    var lastAlertKey = $"{projectCode}_{rule.Id}";
                    var lastAlertTime = _lastAlertTime.GetValueOrDefault(lastAlertKey, DateTime.MinValue);

                    if (now - lastAlertTime > TimeSpan.FromMinutes(5)) // 5分钟冷却时间
                    {
                        await TriggerAlertAsync(projectCode, rule, errorCountInWindow, now);
                        _lastAlertTime[lastAlertKey] = now;
                    }
                    else
                    {
                        _logger.LogDebug("项目 {ProjectCode} 规则 {RuleId} 在冷却期内，跳过报警", projectCode, rule.Id);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "检查报警规则时发生错误: {Message}", ex.Message);
            }
        }

        /// <summary>
        /// 触发报警
        /// </summary>
        private async Task TriggerAlertAsync(string projectCode, AlertRuleModel rule, int errorCount, DateTime now)
        {
            try
            {
                var alertMessage = $"🚨 项目报警通知\n\n" +
                                 $"项目代码: {projectCode}\n" +
                                 $"日志级别: {GetLogLevelName(rule.LogLevel)}\n" +
                                 $"错误数量: {errorCount} 条\n" +
                                 $"时间窗口: {rule.TimeWindow} 分钟\n" +
                                 $"阈值设置: {rule.ThresholdCount} 条\n" +
                                 $"通知方式: {GetNotifyTypeName(rule.NotifyType)}\n" +
                                 $"报警时间: {now:yyyy-MM-dd HH:mm:ss}";

                _logger.LogWarning("触发报警: {Message}", alertMessage);

                // 根据通知类型发送报警
                switch (rule.NotifyType?.ToLower())
                {
                    case "dingtalk":
                        _dingTalkAlertService.RecordErrorLog(projectCode, alertMessage);
                        break;
                    case "email":
                        // TODO: 实现邮件通知
                        _logger.LogInformation("邮件通知功能待实现: {Message}", alertMessage);
                        break;
                    case "sms":
                        // TODO: 实现短信通知
                        _logger.LogInformation("短信通知功能待实现: {Message}", alertMessage);
                        break;
                    default:
                        _logger.LogWarning("未知的通知类型: {NotifyType}", rule.NotifyType);
                        break;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "触发报警时发生错误: {Message}", ex.Message);
            }
        }

        /// <summary>
        /// 获取日志级别名称
        /// </summary>
        private string GetLogLevelName(byte level)
        {
            switch (level)
            {
                case 1:
                    return "Error";
                case 2:
                    return "Warning";
                case 3:
                    return "Information";
                case 4:
                    return "Debug";
                default:
                    return $"Unknown({level})";
            }
        }

        /// <summary>
        /// 获取通知类型名称
        /// </summary>
        private string GetNotifyTypeName(string notifyType)
        {
            if (string.IsNullOrEmpty(notifyType))
                return "未知";

            switch (notifyType.ToLower())
            {
                case "dingtalk":
                    return "钉钉";
                case "email":
                    return "邮件";
                case "sms":
                    return "短信";
                default:
                    return notifyType;
            }
        }

        /// <summary>
        /// 清理过期的跟踪数据
        /// </summary>
        public void CleanupExpiredData()
        {
            var now = DateTime.UtcNow;
            var expiredKeys = new List<string>();

            foreach (var kvp in _errorLogTracker)
            {
                var errorList = kvp.Value;
                lock (errorList)
                {
                    errorList.RemoveAll(t => (now - t).TotalHours > 1);
                    if (errorList.Count == 0)
                    {
                        expiredKeys.Add(kvp.Key);
                    }
                }
            }

            foreach (var key in expiredKeys)
            {
                _errorLogTracker.TryRemove(key, out _);
            }

            _logger.LogDebug("清理过期数据完成，移除了 {Count} 个项目的跟踪数据", expiredKeys.Count);
        }
    }
}